package cn.jk.aspect;

import cn.jk.exception.MyException;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;

@Aspect
@Component
public class MyAspect {


	/**
	 * Advice：Before  正常执行方法之前触发
	 */
//	@Before("anyPublicOperation()")
	public void before(){

	}

	/**
	 * Advice：AfterReturning  正常返回后触发
	 * retVal为方法正常返回的值，这个确实比较强大
	 */
//	@AfterReturning(
//			pointcut="anyPublicOperation()",
//			returning="retVal")
	public void afterReturning(Object retVal) {

	}

	/**
	 * Advice：AfterThrowing 当执行方法抛出异常后触发
	 * throwing 可指定抛出异常的临时变量名称，形参为抛出Throwable得类型，匹配上则会执行当前方法
	 */
//	@AfterThrowing(pointcut = "anyPublicOperation()",throwing = "e")
	public void afterThrowing(MyException e){

	}

	/**
	 * Advice：After
	 * 方法执行完毕后触发
	 */
//	@After("anyPublicOperation()")
	public void after(){

	}

	/**
	 * Advice： Around
	 * 环绕通知，包含整个方法执行的点，由自己定义什么时候执行方法并返回
	 * joinPoint.proceed() 可以被调用一次或者多次甚至不被调用都是合法的，根据这个特点可以实现一个简单的缓存，或者事务管理
	 */
//	@Around("anyPublicOperation()")
	public Object around(ProceedingJoinPoint joinPoint){
		Object proceed = null;
		try {
			proceed = joinPoint.proceed();
		} catch (Throwable throwable) {
			throwable.printStackTrace();
		}
		return proceed;
	}

	/**
	 * 形参注入的方式，匹配第一个参数为map（HashMap<String,String>）的方法，并拿到此参数
	 */
//	@Before(value = "execution(* cn.jk.service.AopService.*(..)) && args(str)")
	public void anyPublicOperationHasMapArgs(String str) {
		// ...
		System.out.println(str);
	}

	@Before(value = "execution(* cn.jk.service.AopService.*(..))")
	public void anyAopServiceMethod() {
		// ...
		System.out.println("拦截了AopService的方法了");
	}

	/**
	 *
	 * @param joinPoint 当前方法执行的切点
	 * @param bean 执行方法得代理对象
	 * @param str 原方法形参str
	 * @param transactional Transactional所注释的参数
	 */
	@Before(value = "execution(* cn.jk.service.AopService.*(..)) && target(bean) && args(str)&& @annotation(transactional)", argNames = "joinPoint,bean,str,transactional")
	public void before(JoinPoint joinPoint,Object bean, String str, Transactional transactional){

		System.out.println(bean);
	}


	/*************************************************以下是声明的切点********************************************************************/


	/**
	 * 匹配所有的public方法
	 */
	@Pointcut("execution(public * *(..))")
	private void anyPublicOperation() {}

	/**
	 * 匹配所有以set开头的方法
	 */
//	@Pointcut("execution(* set*(..))")
	private void anySetMethod() {}

	/**
	 * 匹配所有userService 的方法
	 */
//	@Pointcut("execution(* cn.jk.service.UserService.*(..))")
	private void userService() {}

	/**
	 * 匹配所有Service包下的方法
	 */
//	@Pointcut("execution(* cn.jk.service.*.*(..))")
	private void anyService() {}

	/**
	 * 匹配所有Service子包下的方法
	 */
//	@Pointcut("execution(* cn.jk.service..*.*(..))")
	private void anySubService() {}

	/**
	 * 匹配所有Service包下的方法
	 */
//	@Pointcut("within(cn.jk.service.*)")
	private void withinAnyService() {}

	/**
	 * 匹配所有Service子包下的方法
	 */
//	@Pointcut("within(cn.jk.service..*)")
	private void withinAnySubService() {}

	/**
	 * 匹配所有Service下的方法
	 */
//	@Pointcut("this(cn.jk.service.UserService)")
	private void thisAnyService() {}

	/**
	 * 目标对象所有实现IuserDao接口的方法
	 */
//	@Pointcut("target(cn.jk.dao.IUserDao)")
	private void anyUserDaoMethod() {}

	/**
	 * 所有带一个可序列化参数的方法
	 */
//	@Pointcut("args(java.io.Serializable)")
	private void anyMethodLikeThis() {}

	/**
	 * 所有被@Transactional注释的方法
	 */
//	@Pointcut("@target(org.springframework.transaction.annotation.Transactional)")
	private void anyMethodAnnotatedByTransactional() {}

	/**
	 * 所有被@Transactional注释的方法
	 */
//	@Pointcut("@within(org.springframework.transaction.annotation.Transactional)")
	private void anyMethodAnnotatedByTransactional1() {}

	/**
	 * 所有被@Transactional注释的方法
	 */
//	@Pointcut("@annotation(org.springframework.transaction.annotation.Transactional)")
	private void anyMethodAnnotatedByTransactional2() {}

	/**
	 * 在运行时所有参数被@Nullable注释的方法
	 */
//	@Pointcut("@args(org.springframework.lang.Nullable)")
	private void anyMethodHasArgsAnnotatedByNullable() {}

	/**
	 * 名称为userService的bean的所有方法
	 */
//	@Pointcut("bean(userService)")
	private void beanNamedUserService() {}

	/**
	 * 名称为*Service的bean的所有方法
	 */
//	@Pointcut("bean(*Service)")
	private void beanNamedService() {}

}
